/*
 * ZooInspector
 * 
 * Copyright 2010 Colin Goodheart-Smithe

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package org.apache.zookeeper.inspector.gui;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutionException;

import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.SwingWorker;

import org.apache.zookeeper.inspector.gui.nodeviewer.NodeViewerData;
import org.apache.zookeeper.inspector.gui.nodeviewer.ZooInspectorNodeViewer;
import org.apache.zookeeper.inspector.logger.LoggerFactory;
import org.apache.zookeeper.inspector.manager.ZooInspectorManager;
import org.apache.zookeeper.inspector.manager.ZooInspectorManagerImpl;

/**
 * @author CGSmithe
 * 
 */
public class ZooInspectorPanel extends JPanel implements NodeViewersChangeListener
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 4035146552562401079L;
	private final JButton refreshButton;
	private final JButton disconnectButton;
	private final JButton connectButton;
	private final ZooInspectorNodeViewersPanel nodeViewersPanel;
	private final ZooInspectorTreeViewer treeViewer;
	private final ZooInspectorManager zooInspectorManager;
	private final JButton addNodeButton;
	private final JButton deleteNodeButton;
	private final JButton nodeViewersButton;
	private final JButton aboutButton;
	private final Map<String, String> map = new HashMap<String, String>();
	private final List<String> selects = new ArrayList<String>();
	
	private boolean connect = false;
	
	public boolean isConnect() {
		return connect;
	}

	public void setConnect(boolean connect) {
		treeViewer.getTree().setRowHeight(ZooInspectorManagerImpl.systemFontSize+4);
		NodeViewerData.setCurFont(treeViewer.getTree(), ZooInspectorManagerImpl.systemFontSize);
		this.connect = connect;
	}

	private final List<NodeViewersChangeListener> listeners = new ArrayList<NodeViewersChangeListener>();
	{
		listeners.add(this);
	}

	/**
	 * @param zooInspectorManager
	 */
	public ZooInspectorPanel(final ZooInspectorManager zooInspectorManager)
	{
		this.zooInspectorManager = zooInspectorManager;
		final ArrayList<ZooInspectorNodeViewer> nodeViewers = new ArrayList<ZooInspectorNodeViewer>();
		try
		{
			List<String> defaultNodeViewersClassNames = this.zooInspectorManager
					.getDefaultNodeViewerConfiguration();
			for (String className : defaultNodeViewersClassNames)
			{
				nodeViewers.add((ZooInspectorNodeViewer) Class.forName(className).newInstance());
			}
		}
		catch (Exception ex)
		{
			LoggerFactory.getLogger().error("Error loading default node viewers.", ex);
			JOptionPane.showMessageDialog(ZooInspectorPanel.this,
					"Error loading default node viewers: " + ex.getMessage(), "Error",
					JOptionPane.ERROR_MESSAGE);
		}
		nodeViewersPanel = new ZooInspectorNodeViewersPanel(zooInspectorManager, nodeViewers);
		treeViewer = new ZooInspectorTreeViewer(zooInspectorManager, nodeViewersPanel);
		treeViewer.setZooInspectorPanel(ZooInspectorPanel.this);
		this.setLayout(new BorderLayout());
		JToolBar toolbar = new JToolBar();
		toolbar.setFloatable(false);
		connectButton = new JButton(ZooInspectorIconResources.getConnectIcon());
		connectButton.addKeyListener(new KeyAdapter() {

			@Override
			public void keyReleased(KeyEvent e) {
				if(e.getKeyCode() == KeyEvent.VK_ENTER) {
					connectButton.doClick();
				}
			}
			
		});
		disconnectButton = new JButton(ZooInspectorIconResources.getDisconnectIcon());
		refreshButton = new JButton(ZooInspectorIconResources.getRefreshIcon());
		addNodeButton = new JButton(ZooInspectorIconResources.getAddNodeIcon());
		deleteNodeButton = new JButton(ZooInspectorIconResources.getDeleteNodeIcon());
		nodeViewersButton = new JButton(ZooInspectorIconResources.getChangeNodeViewersIcon());
		aboutButton = new JButton(ZooInspectorIconResources.getInformationIcon());
		toolbar.add(connectButton);
		toolbar.add(disconnectButton);
		toolbar.add(refreshButton);
		toolbar.add(addNodeButton);
		toolbar.add(deleteNodeButton);
		toolbar.add(nodeViewersButton);
		toolbar.add(aboutButton);
		aboutButton.setEnabled(true);
		connectButton.setEnabled(true);
		disconnectButton.setEnabled(false);
		refreshButton.setEnabled(false);
		addNodeButton.setEnabled(false);
		deleteNodeButton.setEnabled(false);
		nodeViewersButton.setEnabled(true);
		nodeViewersButton.setToolTipText("视图管理");
		aboutButton.setToolTipText("关于");
		connectButton.setToolTipText("Zookeeper连接");
		disconnectButton.setToolTipText("断开Zookeeper连接");
		refreshButton.setToolTipText("刷新");
		addNodeButton.setToolTipText("创建节点");
		deleteNodeButton.setToolTipText("删除节点");
		connectButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				if(isConnect()) return;
				setConnect(true);
				ZooInspectorConnectionPropertiesDialog zicpd = new ZooInspectorConnectionPropertiesDialog(
						zooInspectorManager.getConnectionPropertiesTemplate(),
						ZooInspectorPanel.this);
				zicpd.setLocationRelativeTo(ZooInspectorPanel.this);
				zicpd.addWindowListener(new WindowAdapter() {

					@Override
					public void windowClosing(WindowEvent e) {
						ZooInspectorPanel.this.setConnect(false);
					}
					
				});
				zicpd.setVisible(true);
			}
		});
		disconnectButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				disconnect();
			}
		});
		refreshButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				treeViewer.refreshView();
			}
		});
		addNodeButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				final List<String> selectedNodes = treeViewer.getSelectedNodes();
				if (selectedNodes.size() == 1)
				{
					final String nodeName = JOptionPane.showInputDialog(ZooInspectorPanel.this,
							"请输入节点名称", "创建节点",
							JOptionPane.INFORMATION_MESSAGE);
					if (nodeName != null && nodeName.length() > 0)
					{
						SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>()
						{

							@Override
							protected Boolean doInBackground() throws Exception
							{
								return ZooInspectorPanel.this.zooInspectorManager.createNode(
										selectedNodes.get(0), nodeName);
							}

							@Override
							protected void done()
							{
								treeViewer.refreshView();
							}
						};
						worker.execute();
					}
				}
				else
				{
					JOptionPane.showMessageDialog(ZooInspectorPanel.this,
							"请选择一个父节点！！！");
				}
			}
		});
		deleteNodeButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				final List<String> selectedNodes = treeViewer.getSelectedNodes();
				if (selectedNodes.size() == 0)
				{
					JOptionPane.showMessageDialog(ZooInspectorPanel.this,
							"请选择一个节点删除！！！");
				}
				else
				{
					int answer = JOptionPane.showConfirmDialog(ZooInspectorPanel.this,
							"确定要删除选中的所有节点吗?", "删除提示",
							JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
					if (answer == JOptionPane.YES_OPTION)
					{
						SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>()
						{

							@Override
							protected Boolean doInBackground() throws Exception
							{
								for (String nodePath : selectedNodes)
								{
									ZooInspectorPanel.this.zooInspectorManager.deleteNode(nodePath);
								}
								return true;
							}

							@Override
							protected void done()
							{
								treeViewer.refreshView();
							}
						};
						worker.execute();
					}
				}
			}
		});
		nodeViewersButton.addActionListener(new ActionListener()
		{

			public void actionPerformed(ActionEvent e)
			{
				ZooInspectorNodeViewersDialog nvd = new ZooInspectorNodeViewersDialog(JOptionPane
						.getRootFrame(), nodeViewers, listeners, zooInspectorManager);
				nvd.setLocationRelativeTo(null);
				nvd.setVisible(true);
			}
		});
		aboutButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				ZooInspectorAboutDialog zicpd = new ZooInspectorAboutDialog(JOptionPane
						.getRootFrame());
				zicpd.setLocationRelativeTo(null);
				zicpd.setVisible(true);
			}
		});
		JScrollPane treeScroller = new JScrollPane(treeViewer);
		JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treeScroller,
				nodeViewersPanel);
		splitPane.setResizeWeight(0.25);
		this.add(splitPane, BorderLayout.CENTER);
		this.add(toolbar, BorderLayout.NORTH);
		treeViewer.getTree().addKeyListener(new KeyAdapter() {

			@Override
			public void keyReleased(KeyEvent e) {
				if(e.isControlDown() && e.getKeyCode() == KeyEvent.VK_D) {
					deleteNodeButton.doClick();
				}
				if(e.getKeyCode() == 116) {
					refreshButton.doClick();
				}
				if(e.isControlDown() && e.getKeyCode() == KeyEvent.VK_C) {
					List<String> selectedNodes = treeViewer.getSelectedNodes();
					Map<String, String> datas = zooInspectorManager.getDatas(selectedNodes);
					if(datas != null) {
						map.clear();
						map.putAll(datas);
					}
				}
				if(e.isControlDown() && e.getKeyCode() == KeyEvent.VK_V) {
					List<String> selectedNodes = treeViewer.getSelectedNodes();
					selects.addAll(selectedNodes);
					if(!map.isEmpty()) {
						zooInspectorManager.writeDatas(selectedNodes , map);
						refreshButton.doClick();
					}
				}
				if(e.isControlDown() && e.getKeyCode() == KeyEvent.VK_Z) {
					if(!map.isEmpty() && !selects.isEmpty()) {
						zooInspectorManager.deleteDatas(selects , map);
						refreshButton.doClick();
						selects.clear();
					}
				}
				if(e.isControlDown() && e.getKeyCode() == 61) {
					addNodeButton.doClick();
				}
				if(e.isControlDown() && e.getKeyCode() == KeyEvent.VK_I) { 
					List<String> selectedNodes = treeViewer.getSelectedNodes();
					String path = ZooInspectorTreeViewer.getFilePath();
					try {
						if(path == null || path.trim().isEmpty() || !new File(path).exists()) {
							return;
						}
						zooInspectorManager.leadIn(selectedNodes, path);
						JOptionPane.showConfirmDialog(ZooInspectorPanel.this, "数据导入完成","节点数据导入",JOptionPane.PLAIN_MESSAGE);
					} catch (Exception e1) {
						JOptionPane.showConfirmDialog(ZooInspectorPanel.this, "数据导入失败\n"+e1.getMessage(),"节点数据导入",JOptionPane.ERROR_MESSAGE);
						e1.printStackTrace();
					}
				}
				if(e.isControlDown() && e.getKeyCode() == KeyEvent.VK_S) {
					List<String> selectedNodes = treeViewer.getSelectedNodes();
					String path = ZooInspectorTreeViewer.getSavePath();
					try {
						if(path == null || path.trim().isEmpty())
							return;
						int showConfirmDialog = JOptionPane.showConfirmDialog(ZooInspectorPanel.this, "是否导出父节点?", "导出", JOptionPane.YES_NO_OPTION);
						boolean bool = false;
						if(showConfirmDialog==0) {
							bool = true;
						}
						if(showConfirmDialog == -1) {
							JOptionPane.showConfirmDialog(ZooInspectorPanel.this, "导出任务已取消!!!","导出",-1,JOptionPane.WARNING_MESSAGE);
							return;
						}
						boolean leadOut = zooInspectorManager.leadOut(selectedNodes, path , bool);
						if(leadOut) {
							
							JOptionPane.showConfirmDialog(ZooInspectorPanel.this, "数据导出完成","节点数据导出",JOptionPane.PLAIN_MESSAGE);
						} else {
							JOptionPane.showConfirmDialog(ZooInspectorPanel.this, "没有权限导出数据","节点数据导出",JOptionPane.PLAIN_MESSAGE);

						}
					} catch (Exception e1) {
						JOptionPane.showConfirmDialog(ZooInspectorPanel.this, "数据导出失败\n"+e1.getMessage(),"节点数据导出",JOptionPane.ERROR_MESSAGE);
						e1.printStackTrace();
					}
				}
				
			}
			
		});
	}

	/**
	 * @param connectionProps
	 */
	public void connect(final Properties connectionProps)
	{
		SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>()
		{

			@Override
			protected Boolean doInBackground() throws Exception
			{
				boolean connect2 = zooInspectorManager.connect(connectionProps);
				setConnect(false);
				return connect2;
			}

			@Override
			protected void done()
			{
				try
				{
					if (get())
					{
						treeViewer.refreshView();
						connectButton.setEnabled(false);
						disconnectButton.setEnabled(true);
						refreshButton.setEnabled(true);
						addNodeButton.setEnabled(true);
						deleteNodeButton.setEnabled(true);
					}
					else
					{
						JOptionPane.showMessageDialog(ZooInspectorPanel.this,
								"连接Zookeeper失败！！！", "连接提示",
								JOptionPane.ERROR_MESSAGE);
					}
				}
				catch (InterruptedException e)
				{
					LoggerFactory.getLogger().error(
							"Error occurred while connecting to ZooKeeper server", e);
				}
				catch (ExecutionException e)
				{
					LoggerFactory.getLogger().error(
							"Error occurred while connecting to ZooKeeper server", e);
				}
			}

		};
		worker.execute();
	}

	/**
	 * 
	 */
	public void disconnect()
	{
		disconnect(false);
	}

	/**
	 * @param wait
	 */
	public void disconnect(boolean wait)
	{
		SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>()
		{

			@Override
			protected Boolean doInBackground() throws Exception
			{
				return ZooInspectorPanel.this.zooInspectorManager.disconnect();
			}

			@Override
			protected void done()
			{
				try
				{
					if (get())
					{
						treeViewer.clearView();
						connectButton.setEnabled(true);
						disconnectButton.setEnabled(false);
						refreshButton.setEnabled(false);
						addNodeButton.setEnabled(false);
						deleteNodeButton.setEnabled(false);
					}
				}
				catch (InterruptedException e)
				{
					LoggerFactory.getLogger().error(
							"Error occurred while disconnecting from ZooKeeper server", e);
				}
				catch (ExecutionException e)
				{
					LoggerFactory.getLogger().error(
							"Error occurred while disconnecting from ZooKeeper server", e);
				}
			}

		};
		worker.execute();
		if (wait)
		{
			while (!worker.isDone())
			{
				try
				{
					Thread.sleep(100);
				}
				catch (InterruptedException e)
				{
					LoggerFactory.getLogger().error(
							"Error occurred while disconnecting from ZooKeeper server", e);
				}
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seeorg.apache.zookeeper.inspector.gui.NodeViewersChangeListener#
	 * nodeViewersChanged(java.util.List)
	 */
	public void nodeViewersChanged(List<ZooInspectorNodeViewer> newViewers)
	{
		this.nodeViewersPanel.setNodeViewers(newViewers);
	}
}
